/**
 * 20.1.9：移除重写的clone，按照THREE.js的风格来
 * 21.2.6：增加dropCorrectionHead和dropCorrectionTail两个补充属性，更加灵活
 */
let THREE=require('three');
import HardLine from './hard-line';

/**
 * 分段线（每两个点为一段）
 * 不支持箭头
 *
 @param values {object} {name,value}
 color:new THREE.Color(0,1,0),  颜色
 width:0.5,  线宽
 dashSize:0.1,  虚线长
 gapSize:0.1,  虚线空白长
 perspectiveFactor:10,  透视系数
 opacity:1,  透明度
 dashFill:true,  虚线还是实线
 sizeAttenuation:true,  是否启用近大远小
 zOffset:0,  z偏移
 dropCorrection:0.01, 端点丢弃长度（因着色器计算误差端点转角处会有残留）
 dropCorrectionHead:0, 起始端点丢弃长度
 dropCorrectionTail:0, 终止端点丢弃长度

 材质通用属性可获取material进行编辑
 几何体通用属性可获取geometry进行编辑
 */
export default class strips extends HardLine{
    constructor(vertices,values={}){
        super(vertices,values);
        console.warn('this class is deprecated,use ThickLine instead!');
    }

    //---------------------------------------对外属性及方法----------------------------------------

    /**
     * 顶点着色器
     * @returns {string}
     */
    get vertexShader(){
        return [
            'attribute vec3 nextPosition;',
            'attribute float offset;',
            'attribute float distance;',
            'attribute float count;',
            'uniform vec3 color;',
            'uniform float width;',
            'uniform float perspectiveFactor;',
            'uniform bool sizeAttenuation;',
            'varying vec3 vColor;',
            'varying float vDistance;',
            'varying float vDrop;',
            'float computeAspect(){' ,
            '   float aspect=0.5625;' ,
            '   if(projectionMatrix[3][3]==0.0){' ,
            '      float _tan=projectionMatrix[1][1];' ,
            '      float as_tan=1.0/projectionMatrix[0][0];' ,
            '      aspect=1.0/(as_tan*_tan);' ,
            '   }else{' ,
            '      float _height=1.0/projectionMatrix[1][1];' ,
            '      float _width=1.0/projectionMatrix[0][0];' ,
            '      aspect=_height/_width;' ,
            '   }' ,
            '   return aspect;' ,
            '}',
            'void main(){',
            '   vec4 mvPosition=modelViewMatrix*vec4(position,1.0);',
            '   vec4 pmvPosition=projectionMatrix*mvPosition;',
            '   vec4 mvNextPosition=modelViewMatrix*vec4(nextPosition,1.0);',
            '   vec4 nxtP=projectionMatrix*mvNextPosition;',
            '   vec4 curP=pmvPosition;',
            '   vec3 nxt=vec3(nxtP.x/nxtP.w,nxtP.y/nxtP.w,nxtP.z/nxtP.w);',
            '   vec3 cur=vec3(curP.x/curP.w,curP.y/curP.w,curP.z/curP.w);',
            '   vec3 dirOri=nxt-cur;',
            '   vec3 look=vec3(0.0,0.0,1.0);',

            '   vec3 dirCC=mvPosition.xyz/mvPosition.w;',
            '   vec3 dirCN=mvNextPosition.xyz/mvNextPosition.w;',
            '   float dotC=dot(look,dirCC);',
            '   float dotN=dot(look,dirCN);',
            '   if(dotC*dotN<0.){',
            '      if(projectionMatrix[3][3]==0.0)look=vec3(0.,0.,-1.);',
            '   }',

            '   vec3 crs=cross(look,dirOri);',
            '   vec3 dir=normalize(crs);',
            '   float aspect=computeAspect();',
            '   dir.x*=aspect;',
            '   float rad=width;',
            '   if(sizeAttenuation){',
            '       rad*=projectionMatrix[1][1];' ,
            '      gl_Position=vec4(vec3(pmvPosition.xyz)+dir*rad/perspectiveFactor*offset,pmvPosition.w);',
            '   }else{',
            '      gl_Position=vec4(vec3(pmvPosition.xyz)+dir*rad/perspectiveFactor*offset*pmvPosition.w,pmvPosition.w);',
            '   }',
            '   vColor=color;',
            '   vDistance=distance;',
            '   vDrop=count;',
            '}'
        ].join('\n');
    }

    /**
     * 片元着色器
     * @returns {string}
     */
    get fragmentShader(){
        return [
            'uniform float dashSize;',
            'uniform float gapSize;',
            'uniform float opacity;',
            'uniform bool dashFill;',
            'uniform float dropCorrectionHead;',
            'uniform float dropCorrectionTail;',
            'varying float vDistance;',
            'varying vec3 vColor;',
            'varying float vDrop;',
            'void main(){',
            '   float md=mod(vDrop,2.0);',
            '   if(md>1.-dropCorrectionTail||md<dropCorrectionHead){',
            '      discard;',
            '   }',
            '   if(dashFill){',
            '      gl_FragColor=vec4(vColor,opacity);',
            '   }else{',
            '      float dev=mod(vDistance,dashSize+gapSize);',
            '      if(dev>dashSize){',
            '         discard;',
            '      }',
            '      gl_FragColor=vec4(vColor,opacity);',
            '   }',
            '}'
        ].join('\n');
    }

    /**
     * 端点丢弃长度
     */
    get dropCorrection(){
        return this._props.dropCorrection.value;
    }
    set dropCorrection(num){
        this._props.dropCorrection.value=num;
    }

    /**
     * 起始端点丢弃长度
     */
    get dropCorrectionHead(){
        return this._props.dropCorrectionHead.value;
    }
    set dropCorrectionHead(num){
        this._props.dropCorrectionHead.value=num;
    }

    /**
     * 终止端点丢弃长度
     */
    get dropCorrectionTail(){
        return this._props.dropCorrectionTail.value;
    }
    set dropCorrectionTail(num){
        this._props.dropCorrectionTail.value=num;
    }

    /**
     * 更新几何体
     */
    updateGeometry() {
        super.updateGeometry();
        this.geometry.getAttribute('count').copyArray(this._counts);
        this.geometry.getAttribute('count').needsUpdate = true;
    }
    /**
     * 销毁
     */
    dispose() {
        super.dispose();
        this._counts=null;
    }

    //----------------------------------------私有属性及方法--------------------------------------------

    _initProps() {
        super._initProps();
        this._props.remove('arrowMode','arrowLengthRat','arrowWidthRat');
        this._props.add({
            dropCorrection:this._values.dropCorrection||0.01,
            dropCorrectionHead:this._values.dropCorrectionHead||0,
            dropCorrectionTail:this._values.dropCorrectionTail||0,
        });
    }
    _initPropCallback(){
        super._initPropCallback();
        this._props.onKeyChange('dropCorrection',(_new,_old)=>{
            this.material.uniforms.dropCorrectionHead.value=_new;
            this.material.uniforms.dropCorrectionTail.value=_new;
        });
        this._props.onKeyChange('dropCorrectionHead',(_new,_old)=>{
            this.material.uniforms.dropCorrectionHead.value=_new;
        });
        this._props.onKeyChange('dropCorrectionTail',(_new,_old)=>{
            this.material.uniforms.dropCorrectionTail.value=_new;
        });
    }
    _initVariable(){
        super._initVariable();
        let s=this._maxSegments;
        let s1=(2*s-3)*6;
        this._counts=new Float32Array(s1);
    }
    _initGeometry() {
        super._initGeometry();
        this.geometry.setAttribute('count',new THREE.BufferAttribute(this._counts,1));
    }
    _initMaterial(){
        super._initMaterial();
        this.material.uniforms.dropCorrectionHead={value:this._props.dropCorrectionHead.value||this._props.dropCorrection.value};
        this.material.uniforms.dropCorrectionTail={value:this._props.dropCorrectionTail.value||this._props.dropCorrection.value};
        this.material.needsUpdate=true;
    }
    _rectifyPoints(ps) {
        return ps;
    }
    _reRangeData(){
        let reRange=super._reRangeData();
        if(reRange){
            let s1=(2*this._maxSegments-3)*6;
            this._counts=new Float32Array(s1);
            this.geometry.setAttribute('count', new THREE.BufferAttribute(this._counts, 1));
        }
    }
    _getData(){
        this._rectifyVerts=this._rectifyPoints(this._verts);
        if(this._rectifyVerts.length<2){
            console.warn('At least 2 points needed!');
            return;
        }
        this._reRangeData();
        this._pushSolidData(this._rectifyVerts);
    }
    _pushData(i3,i1,c,n,o,ct){
        this._offsets[i1]=o;
        this._counts[i1]=ct;
        this._positions[i3]=c.x;
        this._positions[i3+1]=c.y;
        this._positions[i3+2]=c.z;
        this._nextPositions[i3]=n.x;
        this._nextPositions[i3+1]=n.y;
        this._nextPositions[i3+2]=n.z;
    }
    _pushSolidData(vs){
        let n0=this._tV0;
        let n1=this._tV1;
        for(let i=0;i<vs.length-1;i++){
            let cp=vs[i];
            let np=vs[i+1];
            let c0=i;
            let c1=i+1;
            if(i===0){
                n0.copy(np);
                n1.subVectors(np,cp).normalize().add(np);
                this._pushData(0,0,cp,n0,1,c0);
                this._pushData(3,1,cp,n0,-1,c0);
                this._pushData(6,2,np,n1,1,c1);
                this._pushData(9,3,cp,n0,-1,c0);
                this._pushData(12,4,np,n1,-1,c1);
                this._pushData(15,5,np,n1,1,c1);
            }else{
                let i3=18+(i-1)*36;
                let i1=6+(i-1)*12;
                n0.copy(np);
                n1.subVectors(np,cp).normalize().add(np);
                this._pushData(i3+18,i1+6,cp,n0,1,c0);
                this._pushData(i3+21,i1+7,cp,n0,-1,c0);
                this._pushData(i3+24,i1+8,np,n1,1,c1);
                this._pushData(i3+27,i1+9,cp,n0,-1,c0);
                this._pushData(i3+30,i1+10,np,n1,-1,c1);
                this._pushData(i3+33,i1+11,np,n1,1,c1);
            }
        }
    }
}
